﻿﻿// Google Maps Event Extensions ------------------------------------------------------------------------

// GPolyline extensions (polyclick event and deviation radius managing)
GPolyline.prototype._initialize = GPolyline.prototype.initialize;
GPolyline.prototype._redraw = GPolyline.prototype.redraw;
GPolyline.prototype._normalProj = G_NORMAL_MAP.getProjection();

// overlay methods overriding
GPolyline.prototype.initialize = function(map){
    this._initialize(map);
    this._myMap = map;
    this._myMapDiv = map.getContainer();
    this._routePixels = null;
    this._pixelsToIndex = null;
    this._inTolerance = false;
    this._deviation = -1;
    this._lastClosestPoint = {'absPixel': {'x': 0, 'y': 0}, 'minVertex':-1, 'subrouteIndex':-1};
    this._loadRouteData();
    this._waypoints = null;
    this._waypointVertexes = null;
    this._wpRep = false;
    GEvent.addListener(map, 'zoomend', GEvent.callback(this, this._loadRouteData));
    this._loadRouteData();
    
    // click handling
    var clickHandler = GEvent.callback(this, this._mapClick), me = this, np = this._normalProj;
    GEvent.addListener(map, 'click', 
        function(ov, ll){if (ll){clickHandler(map.fromLatLngToDivPixel(ll), ll, false);}});
    GEvent.addListener(map, 'singlerightclick', 
        function(point, src, ov){clickHandler(point, map.fromDivPixelToLatLng(point), true)});
};

GPolyline.prototype._mapClick = function(point, ll, rightClick){
    var p = {'x':0, 'y':0, 'subrouteIndex':-1};
    var absPixel = this._normalProj.fromLatLngToPixel(ll, this._myMap.getZoom());
    this._getClosestPointOnLines(absPixel, this._routePixels, p);
    var d2 = Math.pow(p.x - absPixel.x, 2) + Math.pow(p.y - absPixel.y, 2);    
    if (d2 < 100){
        var polyLatLng = this._normalProj.fromPixelToLatLng(p, this._myMap.getZoom());
        GEvent.trigger(this, 'polyclick', this, polyLatLng, point, rightClick, p.subrouteIndex);
    }
};

GPolyline.prototype.redraw = function(force){
    this._redraw(force);
    this._loadRouteData();
};

// deviation radius managing
GPolyline.prototype.setDeviationRadius = function(kms){
    this._deviation = kms;
};

GPolyline.prototype.isInDeviation = function(latlng){
    var p = {'x':0, 'y':0, 'subrouteIndex':-1};
    var absP = this._normalProj.fromLatLngToPixel(latlng, this._myMap.getZoom());
    this._getClosestPointOnLines(absP, this._routePixels, p);
    var ll = this._normalProj.fromPixelToLatLng(p, this._myMap.getZoom());
    var dist = latlng.distanceFrom(ll)/1000;
    if (dist <= this._deviation)
        return {'result': true, 'deviation': dist};
    else
        return {'result': false, 'deviation': dist};
};

GPolyline.prototype.registerWaypoints = function(wps, reposition){
    if (wps && wps.length && wps.length > 0){
        this._waypoints = wps;
        this._refreshWaypointVertexes(reposition);
    }
};

GPolyline.prototype._refreshWaypointVertexes = function(reposition){
    if (reposition && this._myMap != null) this._wpRep = true;
    if (this._waypoints != null && this._myMap){
        var currPixel = null;
        if (this._wpRep){
            for (var i=0; i<this._waypoints.length; i++){
                currPixel = this._normalProj.fromLatLngToPixel(this._waypoints[i].getLatLng(), this._myMap.getZoom());
                this._getClosestPointOnLines(currPixel, this._routePixels);
                this._waypoints[i].setLatLng(this.getVertex(this._lastClosestPoint.minVertex));
            }
            this._wpRep = false;
        }
        this._waypointVertexes = new Array(); 
        for (var i=0; i<this._waypoints.length; i++){
            currPixel = this._normalProj.fromLatLngToPixel(this._waypoints[i].getLatLng(), this._myMap.getZoom());
            this._waypointVertexes.push(this._pixelsToIndex[currPixel.x + ', ' + currPixel.y]);
        }
    }
};

GPolyline.prototype._loadRouteData = function(){
    var zoom = this._myMap.getZoom();
    this._pixelsToIndex = new Array(), Px = null, pixString = '';
    this._routePixels = new Array();
    for (var i=0; i<this.getVertexCount(); i++){
        Px = this._normalProj.fromLatLngToPixel(this.getVertex(i), zoom);
        pixString = Px.x + ', ' + Px.y;
        if (this._pixelsToIndex[pixString] == undefined){
            this._pixelsToIndex[pixString] = i;
            this._routePixels.push(Px);
        }
    }
    this._refreshWaypointVertexes(this._wpRep);
};

GPolyline.prototype._getClosestPointOnLines = function(pXy, aXys, obj) {
    var minDist;       
    var fTo;
    var fFrom;
    var x;
    var y;
    var i = 0;
    var dist;
        
    if (aXys.length > 1){
        for (var n = 1 ; n < aXys.length ; n++ ) {
            if (aXys[n].x != aXys[n-1].x) {
                var a = (aXys[n].y - aXys[n-1].y) / (aXys[n].x - aXys[n-1].x);
                var b = aXys[n].y - a * aXys[n].x;
                dist = Math.abs(a*pXy.x + b - pXy.y) / Math.sqrt(a*a+1);
            }
            else 
                dist = Math.abs(pXy.x - aXys[n].x)
            
            // length^2 of line segment 
            var rl2 = Math.pow(aXys[n].y - aXys[n-1].y,2) + Math.pow(aXys[n].x - aXys[n-1].x,2);
            
            // distance^2 of pt to end line segment
            var ln2 = Math.pow(aXys[n].y - pXy.y,2) + Math.pow(aXys[n].x - pXy.x,2);

            // distance^2 of pt to begin line segment
            var lnm12 = Math.pow(aXys[n-1].y - pXy.y,2) + Math.pow(aXys[n-1].x - pXy.x,2);

            // minimum distance^2 of pt to infinite line
            var dist2 = Math.pow(dist,2);
            
            // calculated length^2 of line segment
            var calcrl2 = ln2 - dist2 + lnm12 - dist2;

            // redefine minimum distance to line segment (not infinite line) if necessary
            if (calcrl2 > rl2) 
                dist = Math.sqrt( Math.min(ln2,lnm12) );                               
            
            if ( (minDist == null) || (minDist > dist) ) {
                fTo  = ((Math.sqrt(lnm12 - dist2)) / Math.sqrt(rl2));
                minDist = dist;
                i = n;            
            }  
        }
            
        if (fTo > 1 ) 
                fTo = 1;        

        fFrom = 1-fTo;

        var dx = aXys[i-1].x - aXys[i].x;
        var dy = aXys[i-1].y - aXys[i].y;

        x = aXys[i-1].x - (dx * fTo);
        y = aXys[i-1].y - (dy * fTo);
    }    
    
    var pixString = aXys[i].x + ', ' + aXys[i].y;
    var minVertex = this._pixelsToIndex[pixString];
    var subrouteIndex = 0, subrouteFound = false;
    if (this._waypointVertexes != null){
        while(!subrouteFound && subrouteIndex<this._waypoints.length){
            subrouteFound = (minVertex <= this._waypointVertexes[subrouteIndex]);
            subrouteIndex++;
        }
        if (subrouteFound) subrouteIndex--;
    }
    
    if (obj){
        obj.x = x;
        obj.y = y;
        obj.subrouteIndex = subrouteIndex;
    }else{
        this._lastClosestPoint.absPixel.x = x;
        this._lastClosestPoint.absPixel.y = y;
        this._lastClosestPoint.minVertex = minVertex;
        this._lastClosestPoint.subrouteIndex = subrouteIndex;
    }
};
// -------------------------------------------------------------------------------------------------

// GMarker right click
GMarker.prototype._initialize = GMarker.prototype.initialize;
GMarker.prototype.initialize = function(map){
    this._initialize(map);
    var onMe = false, me = this, timeout = false;
    GEvent.addListener(this, 'mouseover', function(){onMe = true;});
    GEvent.addListener(this, 'mouseout', function(){
        setTimeout(function(){onMe = false;}, MapControl2.NAVIGATOR_IS_IE? 50:0);
    });
    GEvent.addListener(map, 'singlerightclick', function(p, src, ov){
        if (onMe){
            if (MapControl2.NAVIGATOR_IS_IE){
                if (timeout) return;
                timeout = true;
                setTimeout(function(){timeout = false; GEvent.trigger(me, 'rightclick', p, src, me);}, 50);  
            }else
                GEvent.trigger(me, 'rightclick', p, src, me);
        }
    });
};